
#include "ParticleSystem.h"
#include "ParticleEmitter.h"
#include "ParticleModifier.h"
#include "../../Utils/Vector2D.h"
#include "../../Utils/Timer.h"

#include <GL/gl.h>
#include <cassert>
#include <iostream>


ParticleSystem::ParticleSystem(ParticleEmitter *emitter) {
    assert(emitter != NULL);
    emitters.push_back(emitter);
}

ParticleSystem::ParticleSystem(std::vector<ParticleEmitter*> emitters) :
    emitters(emitters) {

    for(unsigned i = 0; i < emitters.size(); i++){
        assert(emitters[i] != NULL);
    }
}

ParticleSystem::ParticleSystem(std::vector<ParticleEmitter*> emitters,
                               std::vector<ParticleModifier*> modifiers) :
    emitters(emitters),
    modifiers(modifiers) {

    for(unsigned i = 0; i < emitters.size(); i++){
        assert(emitters[i] != NULL);
    }

    for(unsigned i = 0; i < modifiers.size(); i++){
        assert(modifiers[i] != NULL);
    }
}



ParticleSystem::~ParticleSystem(){
    for(unsigned i = 0; i < emitters.size(); i++){
        delete emitters[i];
    }
}


void ParticleSystem::update(void){
    std::vector<Particle> new_particles;
    for(unsigned i = 0; i < emitters.size(); i++){
        std::vector<Particle> emitter_new_particles = emitters[i]->emit();
        for(unsigned j = 0; j < emitter_new_particles.size(); j++){
            new_particles.push_back(emitter_new_particles[j]);
        }
    }

    for(unsigned i = 0; i < new_particles.size(); i++){
        particles.push_back(new_particles[i]);
    }

    std::vector<Particle> next_particles;
    for(unsigned i = 0; i < particles.size(); i++){
        particles[i].update();
        if(particles[i].active()){
            next_particles.push_back(particles[i]);
        }
    }

    particles = next_particles;

    for(unsigned i = 0; i < modifiers.size(); i++){
        for(unsigned j = 0; j < particles.size(); j++){
            modifiers[i]->modifyParticle(particles[j]);
        }
    }
}


void ParticleSystem::render(void){
    glPushMatrix();

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    glDepthMask(GL_FALSE);

    for(unsigned i = 0; i < particles.size(); i++){
        particles[i].render();
    }

    glDepthMask(GL_TRUE);
    glDisable(GL_BLEND);

    glPopMatrix();
}

bool ParticleSystem::active(void){
    return particles.size() > 0;
}

